<?php

namespace App\Console\Commands;

use App\Common\Libs\RmqClient;
use App\Consts\CacheKeyConst;
use App\Consts\GlobalConst;
use Illuminate\Support\Facades\Cache;

class RabbitMQWorkCommand extends BaseCommand
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'rabbitmq:work {--action=}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Start a rabbitMQ connection and wait for consumer queue from exchanges.';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     * @throws \Exception
     */
    public function handler()
    {
        $action = $this->action;
        if (method_exists(self::class, $action)) {
            return $this->$action();
        }
        return false;
    }

    /**
     * Start mq
     *
     * @return bool
     * @throws \Exception
     */
    public function start()
    {
        if (Cache::store('redis')->get(CacheKeyConst::BLOCKING_RABBIT_MQ_STATUS)) {
            return true;
        }
        $uid = uniqid();
        $exchange = GlobalConst::RMQ_EXCHANGE_MSG_CENTER;
        $queue = GlobalConst::RMQ_QUEUE_MSG_CENTER;
        $info = "[RMQ][WORK][START] - " . json_encode([
                'exchange' => $exchange,
                'queue' => $queue,
                'uid' => $uid,
            ]);
        $this->logger($info);
        Cache::store('redis')->put(CacheKeyConst::BLOCKING_RABBIT_MQ_STATUS, 1, 30 * 1440);
        $res = RmqClient::getInstance()->consumer($exchange, $queue);
        $info = "[RMQ][WORK][END] - " . json_encode([
                'exchange' => $exchange,
                'queue' => $queue,
                'result' => $res,
                'uid' => $uid,
                'res' => $res
            ]);
        $this->logger($info);
        if (isset($res['code']) && $res['code'] && false === strpos($res['msg'], 'channel mismatch')) {
            throw new \Exception($res['msg'], $res['code']);
        }
        return true;
    }

    /**
     * Stop mq
     *
     * @return bool|array
     */
    public function stop()
    {
        // clear blocking cache
        Cache::store('redis')->forget(CacheKeyConst::BLOCKING_RABBIT_MQ_STATUS);
        $rabbitMQ = RmqClient::getInstance();
        $exchange = GlobalConst::RMQ_EXCHANGE_MSG_CENTER;
        $queue = GlobalConst::RMQ_QUEUE_MSG_CENTER;
        $body = ['heartbeat' => true, 'time' => time()];
        $res = $rabbitMQ->publisher($exchange, $queue, $body);
        // log info
        $info = "[RMQ][WORK][STOP] - " . json_encode([
                'exchange' => $exchange,
                'queue' => $queue,
                'uid' => $this->uid,
                'res' => $res
            ]);
        $this->logger($info);
        if(isset($res['code'])){
            return !$res['code'] ? true : $res;
        }
        // finished
        return $res;
    }

    /**
     * Reload mq
     *
     * @return bool
     * @throws \Exception
     */
    public function reload()
    {
        $this->stop();
        // blocking with 5 s
        sleep(5);
        $this->start();
        return true;
    }

    /**
     * Check mq
     *
     * @return bool
     * @throws \Exception
     */
    public function check()
    {
        return $this->start();
    }

}
